home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / procdoggie / uprocessguts.p < prev    next >
Encoding:
Text File  |  2000-09-28  |  82.7 KB  |  2,287 lines

  1. {
  2.     File:        UProcessGuts.p
  3.  
  4.     Contains:    Process Manager-related code that’s specific to ProcDoggie is contained in
  5.                 this unit.  Mainly, this code handles the user interface aspects of this
  6.                 program that relate to the Process Manager, such as the Process List window,
  7.                 the Process Information windows, and most of the menus.
  8.     
  9.                 The Process List window displays a list of all active processes.  It allows
  10.                 the user to click on one or more of the process names and then use menu
  11.                 commands to operate on those selected processes.
  12.     
  13.                 Process Information windows display information about the selected active
  14.                 processes.  The information includes the process’s name, type, creator, SIZE
  15.                 resource flags, partition size, and free memory availability.
  16.     
  17.                 When the user chooses to launch an application, routines in this unit are
  18.                 called to ask the user what process to launch and optionally what documents
  19.                 to open or print, depending on the current launch mode.
  20.     
  21.                 This unit also maintains the current launch mode.  The launch mode indicates
  22.                 whether the user wants to simply launch an application, launch an application
  23.                 along with documents to open, and launch an application with documents to
  24.                 print.  The launch mode is global for this application, and affects the way
  25.                 the menu commands that launch applications work.
  26.  
  27.     Written by: Forrest Tanaka    
  28.  
  29.     Copyright:    Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
  30.  
  31.                 You may incorporate this Apple sample source code into your program(s) without
  32.                 restriction. This Apple sample source code has been provided "AS IS" and the
  33.                 responsibility for its operation is yours. You are not permitted to redistribute
  34.                 this Apple sample source code as "Apple sample source code" after having made
  35.                 changes. If you're going to re-distribute the source, we require that you make
  36.                 it clear in the source that the code was descended from Apple sample source
  37.                 code, but that you've made changes.
  38.  
  39.     Change History (most recent first):
  40.                 7/27/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  41.                 
  42.  
  43. }
  44. UNIT UProcessGuts;
  45.  
  46. {[j=20/57/1$] Pasmat Options}
  47.  
  48. INTERFACE
  49.  
  50.  
  51. (*******************************************************************************
  52. * Units
  53. *******************************************************************************)
  54.  
  55.     USES
  56.         UProcessUtils
  57.         ;
  58.  
  59.  
  60. (*******************************************************************************
  61. * SetLaunchMode - Set the launch mode
  62. *
  63. * This routine is called to set the launching mode to the mode specified by the
  64. * "newMode" parameter.  A launch mode of "kJustLaunch" simply launches an
  65. * application or desk accessory, "kOpenLaunch" launches an application with one
  66. * or more documents for the launched application to open, "kPrintLaunch"
  67. * launches an application with one or more documents for the launched
  68. * application to print.  The launch modes are declared in UProcessUtils.p.
  69. *******************************************************************************)
  70.  
  71.     PROCEDURE SetLaunchMode (newMode: LaunchModeCode);
  72.  
  73.  
  74. (*******************************************************************************
  75. * GetLaunchMode - Get the launch mode
  76. *
  77. * The current launch mode is returned.  For details about launching modes, see
  78. * the description of the SetLaunchMode routine.
  79. *******************************************************************************)
  80.  
  81.     FUNCTION GetLaunchMode: LaunchModeCode;
  82.  
  83.  
  84. (*******************************************************************************
  85. * IsProcessListWindow - Is a WindowPtr a pointer to a process list window?
  86. *
  87. * When I want to find out whether a window that I have a pointer to is a process
  88. * list window or not, I call this routine.  It returns TRUE if aWindow is a
  89. * pointer to a process list window, FALSE if it isn’t.  If aWindow is NIL, then
  90. * IsProcessListWindow returns FALSE.
  91. *******************************************************************************)
  92.  
  93.     FUNCTION IsProcessListWindow (aWindow: WindowPtr): Boolean;
  94.  
  95.  
  96. (*******************************************************************************
  97. * CreateProcessListWindow - Create a process list window
  98. *
  99. * This routine is called to create a new Process List window visible and
  100. * centered on the main screen.  A pointer to the window is returned.  If there
  101. * isn’t enough memory for the window, or if some other problem happened to make
  102. * it impossible to create the window, then CreateProcessListWindow puts up an
  103. * alert indicating this to the user, and then it returns NIL.
  104. *******************************************************************************)
  105.  
  106.     FUNCTION CreateProcessListWindow: WindowPtr;
  107.  
  108.  
  109. (*******************************************************************************
  110. * IdleProcessListWindow - Keep the process list window up to date
  111. *
  112. * IdleProcessListWindow updates the process list window specified by
  113. * processListWindow so that it reflects the status of the processes that are
  114. * currently open.  It’s called once per main event loop iteration.
  115. *******************************************************************************)
  116.  
  117.     PROCEDURE IdleProcessListWindow (processListWindow: WindowPtr);
  118.  
  119.  
  120. (*******************************************************************************
  121. * DrawProcessListWindow - Draw the contents of the process list window
  122. *
  123. * Whenever an update event is received for the process list window, the routine
  124. * is called to draw into the window.  Since the process list covers the entire
  125. * window, the only thing to be done is to call the List Manager to draw the
  126. * list.  processListWindow is a pointer to the process list window.
  127. *******************************************************************************)
  128.  
  129.     PROCEDURE DrawProcessListWindow (processListWindow: WindowPtr);
  130.  
  131.  
  132. (*******************************************************************************
  133. * ClickProcessListWindow - Handle a mouse click in the process list window
  134. *
  135. * When a mouse click is detected in the content region of the process list
  136. * window specified by processListWindow, this routine is called to handle it.
  137. * It allows the user to select a process or several processes in the list.  If
  138. * the user double-clicks on a process, then that process and any other selected
  139. * processes are brought to the front.
  140. *
  141. * clickEvent is the mouse-down event that was in the process list window.
  142. *******************************************************************************)
  143.  
  144.     PROCEDURE ClickProcessListWindow (processListWindow: WindowPtr;
  145.                                       clickEvent:        EventRecord);
  146.  
  147.  
  148. (*******************************************************************************
  149. * ActivateProcessListWindow - Handle an activate/deactivate event
  150. *
  151. * Whenever an activate or deactivate event is received for the process list
  152. * window specified by processListWindow, this routine is called to handle the
  153. * event.  If the event was an activate event, then becomingActive is TRUE.  If
  154. * the event was a deactivate event, then becomingActive is FALSE.
  155. *******************************************************************************)
  156.  
  157.     PROCEDURE ActivateProcessListWindow (processListWindow: WindowPtr;
  158.                                          becomingActive:    Boolean);
  159.  
  160.  
  161. (*******************************************************************************
  162. * FixProcessListMenus - Undim menu items for process list window
  163. *
  164. * Any menus that should be available when the process list window is in front
  165. * are undimmed if the current conditions are appropriate.
  166. *******************************************************************************)
  167.  
  168.     PROCEDURE FixProcessListMenus (processListWindow: WindowPtr);
  169.  
  170.  
  171. (*******************************************************************************
  172. * IsProcessInfoWindow - Is a WindowPtr a pointer to a process info window?
  173. *
  174. * When I want to find out whether a window that I have a pointer to is a process
  175. * info window or not, I call this routine.  It returns TRUE if aWindow is a
  176. * pointer to a process info window, FALSE if it isn’t.  If aWindow is NIL, then
  177. * IsProcessInfoWindow returns NIL.
  178. *******************************************************************************)
  179.  
  180.     FUNCTION IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
  181.  
  182.  
  183. (*******************************************************************************
  184. * IdleProcessInfoWindow - Give the specified process info window some idle time
  185. *
  186. * This routine is called once per event loop iteration.  It gives the specified
  187. * process info window some idle time to update the memory indicator.
  188. *******************************************************************************)
  189.  
  190.     PROCEDURE IdleProcessInfoWindow (processInfoWindow: WindowPtr);
  191.  
  192.  
  193. (*******************************************************************************
  194. * DrawProcessInfoWindow - Draw the contents of the process info window
  195. *
  196. * Whenever an update event is received for the process info window, the routine
  197. * is called to draw the static items into the window.
  198. *******************************************************************************)
  199.  
  200.     PROCEDURE DrawProcessInfoWindow (processInfoWindow: WindowPtr);
  201.  
  202.  
  203. (*******************************************************************************
  204. * FixProcessInfoMenus - Undim menu items for process information window
  205. *
  206. * Any menus that should be available when a process information window is in
  207. * front are undimmed if the current conditions are appropriate.
  208. *******************************************************************************)
  209.  
  210.     PROCEDURE FixProcessInfoMenus (processInfoWindow: WindowPtr);
  211.  
  212.  
  213. (*******************************************************************************
  214. * DoWindowClose - Window closing bottleneck
  215. *
  216. * As new kinds of windows are added to this application, this routine will have
  217. * to be able to detect the new kind of window and dispatch to the routine that
  218. * handles close requests for that kind of window.
  219. *
  220. * As we only have one kind of window that's closable at the moment
  221. * (process info windows), this routine simply checks whether eventWind is
  222. * such a window, and closes it if it is.
  223. *******************************************************************************)
  224.  
  225.     PROCEDURE DoWindowClose (eventWind: WindowPtr);
  226.  
  227.  
  228. (*******************************************************************************
  229. * IdleAllProcessWindows - Give every open process window idle time
  230. *
  231. * IdleAllProcessWindows is called to give the process list window and all open
  232. * process info windows some idle time.  This routine is called once per main
  233. * event loop iteration.
  234. *******************************************************************************)
  235.  
  236.     PROCEDURE IdleAllProcessWindows;
  237.  
  238.  
  239. (*******************************************************************************
  240. * DoLaunchInFront - Launch a process to the front
  241. *
  242. * When the user wants to launch a process and have it brought to the front, this
  243. * routine is called.  It allows the user to choose a process through Standard
  244. * File.  That application is then launched and brought to the front.
  245. *******************************************************************************)
  246.  
  247.     PROCEDURE DoLaunchInFront;
  248.  
  249.  
  250. (*******************************************************************************
  251. * DoLaunchInBack - Launch a process to the back
  252. *
  253. * When the user wants to launch a process and have it sent to the back of all of
  254. * the open processes, this routine is called.  It allows the user to choose a
  255. * process through Standard File.  That process is then launched and sent to the
  256. * back.
  257. *******************************************************************************)
  258.  
  259.     PROCEDURE DoLaunchInBack;
  260.  
  261.  
  262. (*******************************************************************************
  263. * DoLaunchTo - Launch a process and terminate self
  264. *
  265. * When the user wants to launch a process and then immediately quit ProcDoggie,
  266. * this routine is called.  It allows the user to choose a process through
  267. * Standard File.  That process is then launched and brought to the front, and
  268. * then ProcDoggie is immediately terminated.
  269. *******************************************************************************)
  270.  
  271.     PROCEDURE DoLaunchTo;
  272.  
  273.  
  274. (*******************************************************************************
  275. * DoLaunchMode - Handle Simple Launch, Open on Launch, Print on Launch commands
  276. *
  277. * This routine is called when a launch mode menu item is chosen.  The launch
  278. * mode items are in the file menu and are the “Simple Launch,” “Open Documents
  279. * on Launch,” and “Print Documents on Launch” items.
  280. *******************************************************************************)
  281.  
  282.     PROCEDURE DoLaunchMode (modeItem: Integer);
  283.  
  284.  
  285. (*******************************************************************************
  286. * DoBringProcessToFront - Bring an open process to the front
  287. *
  288. * When the user chooses the Bring to Front menu item, this routine is called to
  289. * bring all the selected process to the front in the order that they appear in
  290. * the process list window specified by processListWindow.  For the moment, it
  291. * won’t bring it’s own application (ProcDoggie) to the front.  I don’t know how
  292. * or whether I’ll be able to fix that.
  293. *******************************************************************************)
  294.  
  295.     PROCEDURE DoBringProcessToFront (processListWindow: WindowPtr);
  296.  
  297.  
  298. (*******************************************************************************
  299. * DoGetProcessInfo - Get information about selected processes
  300. *
  301. * This routine is called when the user desires information about the processes
  302. * selected in the process list window specified by the "processListWindow"
  303. * parameter.
  304. *******************************************************************************)
  305.  
  306.     PROCEDURE DoGetProcessInfo (processListWindow: WindowPtr);
  307.  
  308.  
  309. (*******************************************************************************
  310. * DoTerminateProcess - Terminate the selected processes
  311. *
  312. * This routine is called when the user wants to terminate the processes selected
  313. * in the process list window specified by the "processListWindow" parameter.
  314. *******************************************************************************)
  315.  
  316.     PROCEDURE DoTerminateProcess (processListWindow: WindowPtr);
  317.  
  318.  
  319. (*******************************************************************************
  320. * InitProcessGuts - Initialise this module
  321. *******************************************************************************)
  322.  
  323.     PROCEDURE InitProcessGuts;
  324.  
  325.  
  326. IMPLEMENTATION
  327.  
  328.     uses
  329.         TextUtils
  330.         ,Lists
  331.         ,Fonts
  332.         ,GestaltEqu
  333.         ,Resources
  334.         ,StandardFile
  335.         ,Palettes
  336.         ,LowMem
  337.         ,fp
  338.  
  339.         ,UEmergMem
  340.         ,UDialogUtils
  341.         ,UProcessLDEF        
  342.         ,UMenuHandler
  343.         ;
  344.         
  345.  
  346. (*******************************************************************************
  347. * Constants
  348. *******************************************************************************)
  349.  
  350.     CONST
  351.         rProcessListWindID = 128; {Resource ID of process list window template}
  352.         rProcessInfoWindID = 129; {Resource ID of process info window template}
  353.         rProcessInfoDitlID = 129; {Resource ID of process info dialog item list}
  354.  
  355.         kProcessListWindKind = 8;    {In windowKind field of process list windows}
  356.         kProcessInfoWindKind = 9;    {In windowKind field of process info windows}
  357.         kActivateList        = TRUE; {Pass to LActivate to specify activate list}
  358.         kScrollBarWidth      = 16;   {Width of scroll bar in pixels}
  359.  
  360.         rAppOrDAStringID = 128; {Resource ID of Application or DA string}
  361.         kAppStringInd    = 1;   {Index for Application string}
  362.         kDAStringInd     = 2;   {Index for Desk Accessory string}
  363.  
  364.         rCheckMarkID = 128; {Resource ID of checkmark string}
  365.  
  366.         kProcessNameItem   = 1;  {Dialog item # of process name}
  367.         kAppOrDAItem       = 2;  {Dialog item # of Application/DA string}
  368.         kTotalSizeItem     = 5;  {Dialog item # of Total Size readout}
  369.         kFreeSpaceItem     = 6;  {Dialog item # of Free Space readout}
  370.         kMemIndicatorItem  = 7;  {Dialog item # of partition memory indicator}
  371.         kGrayLineItem0     = 8;  {Dialog item # of first gray line}
  372.         kTypeItem          = 11; {Dialog item # of TYPE item}
  373.         kCreatorItem       = 12; {Dialog item # of Creator item}
  374.         kGrayLineItem1     = 13; {Dialog item # of second gray line}
  375.         kSusResChkItem     = 14; {Dialog item # of suspend/resume checkmark}
  376.         kWindActChkItem    = 15; {Dialog item # of window activate checkmark}
  377.         kGetClickChkItem   = 16; {Dialog item # of Get front click checkmark}
  378.         kAppDiedChkItem    = 17; {Dialog item # of App Died checkmark}
  379.         kStationeryChkItem = 18; {Dialog item # of Stationery checkmark}
  380.         kCanBackChkItem    = 19; {Dialog item # of Can Background checkmark}
  381.         kOnlyBackChkItem   = 20; {Dialog item # of Only Background checkmark}
  382.         kHighLevelChkItem  = 21; {Dialog item # of High-Level Evt checkmark}
  383.         kRHighLevelChkItem = 22; {Dialog item # of Remote High-Level checkmark}
  384.         kMultiUserChkItem  = 23; {Dialog item # of Multi-user Launch checkmark}
  385.         k32BitCleanChkItem = 24; {Dialog item # of 32-Bit Clean checkmark}
  386.         kUseTextEditServicesChkItem = 25; {Dialog item # of Use TextEdit Services checkmark}
  387.         kDisplayManagerAwareChkItem = 26; {Dialog item # of Display Manager Aware checkmark}
  388.  
  389.         kUsedColor = 2; {Process Info window palette color for used memory}
  390.         kFreeColor = 3; {Process Info window palette color for free memory}
  391.  
  392.  
  393. (*******************************************************************************
  394. * Types
  395. *******************************************************************************)
  396.  
  397.     TYPE
  398.         {Pointer to canonical format for number strings}
  399.         NumFormatStringPtr = ^NumFormatString;
  400.  
  401.  
  402. (*******************************************************************************
  403. * Variables
  404. *******************************************************************************)
  405.  
  406.     VAR
  407.         gProcessListLDEF: ListDefUPP;
  408.         gEqualPSNUPP : ListSearchUPP;
  409.         gAppDAFilterUPP: FileFilterUPP;
  410.         
  411.     VAR
  412.         gLaunchMode: LaunchModeCode; {Open documents? Print documents?}
  413.  
  414.  
  415. {$S ProcessGuts}
  416. (*******************************************************************************
  417. * Public: SetLaunchMode
  418. *
  419. * The global variable, "gLaunchMode", is set to the launch mode specified by
  420. * "newMode".
  421. *******************************************************************************)
  422.  
  423.     PROCEDURE SetLaunchMode (newMode: LaunchModeCode);
  424.  
  425.     BEGIN
  426.         gLaunchMode := newMode
  427.     END;
  428.  
  429.  
  430. {$S ProcessGuts}
  431. (*******************************************************************************
  432. * Public: GetLaunchMode
  433. *
  434. * The value of the global variable, "gLaunchMode", is returned.
  435. *******************************************************************************)
  436.  
  437.     FUNCTION GetLaunchMode: LaunchModeCode;
  438.  
  439.     BEGIN
  440.         GetLaunchMode := gLaunchMode
  441.     END;
  442.  
  443.  
  444. {$S Main}
  445. (*******************************************************************************
  446. * Public: IsProcessListWindow
  447. *
  448. * I store a unique code in the windowKind field of every window I create so that
  449. * I can identify the kind of window it is later… like now!  I check to see if
  450. * the windowKind field of aWindow is kProcessListWindKind or not.  If it is, I
  451. * know it’s a process list window, and so IsProcessListWindow returns TRUE.
  452. *******************************************************************************)
  453.  
  454.     FUNCTION IsProcessListWindow (aWindow: WindowPtr): Boolean;
  455.  
  456.     BEGIN
  457.         IF aWindow <> NIL THEN
  458.             IsProcessListWindow := WindowPeek(aWindow)^.windowKind =
  459.                     kProcessListWindKind
  460.         ELSE
  461.             IsProcessListWindow := FALSE
  462.     END;
  463.  
  464.  
  465. {$S ProcessGuts}
  466. (*******************************************************************************
  467. * Public: CreateProcessListWindow
  468. *
  469. * I store the constant kProcessListWindKind into the windowKind field of the new
  470. * window.  When the routine IsProcessListWindow is called, it uses this field to
  471. * identify a window as a process list window.
  472. *
  473. * See the UWindowHandler unit for code to create a new window.
  474. *******************************************************************************)
  475.  
  476.     FUNCTION CreateProcessListWindow: WindowPtr;
  477.  
  478.         CONST
  479.             kDrawList      = TRUE; {Pass to LNew; list must be drawn immediately}
  480.             kHasGrow       = TRUE; {Pass to LNew; list has grow box}
  481.             kHasHorzScroll = TRUE; {Pass to LNew; list has a horizontal scroll bar}
  482.             kHasVertScroll = TRUE; {Pass to LNew; list has a vertical scroll bar}
  483.  
  484.         VAR
  485.             aWindow:        WindowPtr;  {Pointer to the process list window}
  486.             processList:    ListHandle; {Handle to the list of processes}
  487.             listRect:       Rect;       {Rectangle of list in window coords}
  488.             listDimensions: Rect;       {Dimensions of list in cells}
  489.             cellSize:       Point;      {Size of cell in pixels}
  490.             currFont:       FontInfo;   {Information about current port’s font}
  491.  
  492.         PROCEDURE HandleError (messageClass: Integer;
  493.                                messageIndex: Integer);
  494.  
  495.             VAR
  496.                 junkError: OSErr;
  497.                 junkItemHit: Integer; {Result of alert; ignored}
  498.  
  499.         BEGIN
  500.             IF aWindow <> NIL THEN
  501.                 BEGIN
  502.                     CloseWindow (aWindow);
  503.                     DisposePtr (Ptr(aWindow))
  504.                 END;
  505.             junkError := ShowStopAlert (messageClass, messageIndex, junkItemHit);
  506.             gError := noErr;
  507.             CreateProcessListWindow := NIL;
  508.             EXIT (CreateProcessListWindow)
  509.         END;
  510.  
  511.     BEGIN
  512.         aWindow := NIL;
  513.  
  514.         (* Create the new window *)
  515.         aWindow := CreateWindow (rProcessListWindID);
  516.         IF gError <> noErr THEN
  517.             IF gError = memFullErr THEN
  518.                 HandleError (rMemErrMessages, kMemErrProcListOpenMsg)
  519.             ELSE IF gError = resNotFound THEN
  520.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  521.             ELSE IF gError = dsSysErr THEN
  522.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  523.  
  524.         (* Set up the window *)
  525.         SetPort (aWindow);
  526.         WindowPeek(aWindow)^.windowKind := kProcessListWindKind;
  527.         TextFont (applFont);
  528.  
  529.         (* Create the process list *)
  530.         GetFontInfo ((*<*)currFont);
  531.         listRect := aWindow^.portRect;
  532.         listRect.right := listRect.right - kScrollBarWidth + 1;
  533.         SetRect ((*<*)listDimensions, 0, 0, 1, 0);
  534.         cellSize.h := listRect.right - listRect.left;
  535.         cellSize.v := currFont.ascent + currFont.descent + currFont.leading;
  536.         processList := LNew (listRect, listDimensions, cellSize, 128, aWindow,
  537.                 kDrawList, NOT kHasGrow, NOT kHasHorzScroll, kHasVertScroll);
  538.         IF FailLowMemory (0) THEN
  539.             HandleError (rMemErrMessages, kMemErrProcListOpenMsg);
  540.  
  541.         (* Install our real LDEF into the refCon so that the stub will call it.*)
  542.         processList^^.refCon := longint(gProcessListLDEF);
  543.         
  544.         (* Make sure the list is activated *)
  545.         LActivate (kActivateList, processList);
  546.  
  547.         (* Save a handle to the list in the refCon of the window *)
  548.         SetWRefCon (aWindow, LongInt (processList));
  549.  
  550.         (* Set the new window as the current GrafPort and return *)
  551.         SetPort (aWindow);
  552.         CreateProcessListWindow := aWindow
  553.     END;
  554.  
  555.  
  556. {$S ProcessGuts}
  557. (*******************************************************************************
  558. * Private: EqualPSN - List Manager search proc
  559. *
  560. * The List Manager’s LSearch function can take a pointer to a routine that
  561. * checks to see if a record matches an entry in the list.  The routine must have
  562. * an interface identical to IUMagIDString.  EqualPSN is the routine that I pass
  563. * to LSearch in the IdleProcessListWindow routine.  It compares the process
  564. * serial number passed in testPSN against the process serial number contained in
  565. * the ProcessListInfoRec of a cell.  Because I already know the lengths of
  566. * ProcessListInfoRecs and ProcessSerialNumber records, I ignore the aLen and
  567. * bLen parameters.
  568. *
  569. * If the two process serial numbers refer to the same process, then EqualPSN
  570. * returns 0, otherwise it returns 1.
  571. *******************************************************************************)
  572.  
  573.     FUNCTION EqualPSN (processInfo: ProcessListInfoPtr;
  574.                        testPSN:     ProcessSerialNumberPtr;
  575.                        aLen:        Integer;
  576.                        bLen:        Integer): Integer;
  577.  
  578.         VAR
  579.             equal: Boolean; {TRUE if PSNs are equal}
  580.             error: OSErr;
  581.  
  582.     BEGIN
  583.         {$unused aLen}
  584.         {$unused bLen}
  585.         error := SameProcess (testPSN^, processInfo^.serialNumber, (*<*)equal);
  586.         IF equal THEN
  587.             EqualPSN := 0
  588.         ELSE
  589.             EqualPSN := 1
  590.     END;
  591.  
  592.  
  593. {$S ProcessGuts}
  594. (*******************************************************************************
  595. * Private: SetProcessListInfo - Set process list cell info
  596. *
  597. * SetProcessListInfo sets the cell specified by row (I’m only using one column,
  598. * so only the row matters) of the list specified by procList to the information
  599. * in procInfo.  My lists contain ProcessListInfoRecs, which contain only two of
  600. * the fields in ProcessInfoRecs (process name and process serial number), so I
  601. * just copy these two fields from procInfo into listInfo.  I then use LSetCell
  602. * to copy listInfo into the list.
  603. *******************************************************************************)
  604.  
  605.     PROCEDURE SetProcessListInfo (procInfo: ProcessInfoRec;
  606.                                   row:      Integer;
  607.                                   procList: ListHandle);
  608.  
  609.         VAR
  610.             listInfo: ProcessListInfoRec; {Process info from List Mgr list}
  611.             newCell:  Cell;               {Cell in which to set information}
  612.  
  613.     BEGIN
  614.         BlockMove (Ptr(procInfo.processName), @listInfo.processName,
  615.                 ORD (procInfo.processName^ [0]) + 1);
  616.  
  617.         (* Copy the process serial number *)
  618.         listInfo.serialNumber := procInfo.processNumber;
  619.  
  620.         (* Set the specified cell to the new ProcessListInfoRec *)
  621.         newCell.h := 0;
  622.         newCell.v := row;
  623.         LSetCell (Ptr(@listInfo), SIZEOF (ProcessListInfoRec), newCell, procList)
  624.     END;
  625.  
  626.  
  627. {$S ProcessGuts}
  628. (*******************************************************************************
  629. * Public: IdleProcessListWindow
  630. *
  631. * I’m using a simple algorithm to keep the process list window’s process list
  632. * updated to the Process Manager’s process list, but it’ll probably be tough to
  633. * describe.  Here goes. . .
  634. *
  635. * I compare the process serial number of each entry in the Process Manager’s
  636. * list against the process serial number of the corresponding entry in
  637. * the process list window’s list.  If they match, then I just go on to the next
  638. * entries of the lists.  If they don’t match, then I search the window’s list in
  639. * case the matching process is farther down.  If I do find it farther down, then
  640. * I assume that the processes in the window’s list that come between the
  641. * matching entries in the two lists were deleted.  So, I delete those rows.  If
  642. * I don’t find it farther down, then I assume that the entry is new.  I then
  643. * insert a new row in the corresponding position of the window’s list and copy
  644. * the process information to it.
  645. *
  646. * If I run out of rows in the window’s list before getting through the entire
  647. * Process Manager list, then I just keep adding new rows to the end of the
  648. * window’s list and copying over the balance.
  649. *
  650. * If I go through the entire Process Manager list but there are left-over
  651. * entries in the window’s list, then I just delete those left-overs.
  652. *
  653. * So, that’s the algorithm.  It was the most efficient one I could come up with
  654. * that wasn’t even harder to explain.  Beware: some parts of this routine have
  655. * only gotten minimal testing, so I wouldn’t be surprised if you find bugs.
  656. *******************************************************************************)
  657.  
  658.     PROCEDURE IdleProcessListWindow (processListWindow: WindowPtr);
  659.  
  660.         VAR
  661.             procNum:        ProcessSerialNumber; {Serial number of open processes}
  662.             procInfo:       ProcessInfoRec;      {Process info from Proc Mgr list}
  663.             procName:       Str255;              {Name of the process}
  664.             listInfo:       ProcessListInfoRec;  {Process info from List Mgr list}
  665.             listInfoLength: Integer;             {Size of ProcessListInfoRec}
  666.             currCell:       Cell;                {List cell being checked}
  667.             matchCell:      Cell;                {Cell with matching PSN}
  668.             procList:       ListHandle;          {Handle to List Mgr process list}
  669.             foundMatch:     Boolean;             {Found matching List Mgr entry}
  670.             equal:          Boolean;             {Proc and List Mgr elements match}
  671.             addedProcess:   Boolean;             {TRUE if a process added to list}
  672.             error:          OSErr;
  673.             junkError:        OSErr;
  674.             junkItemHit:    Integer;             {Result of alert; ignored}
  675.  
  676.     BEGIN
  677.         (* Get the List Manager’s copy of the process list *)
  678.         procList := ListHandle(GetWRefCon (processListWindow));
  679.  
  680.         (* Start checking from start of List Mgr and Process Mgr lists *)
  681.         addedProcess := FALSE;
  682.         currCell.v := 0;
  683.         currCell.h := 0;
  684.         procNum.highLongOfPSN := 0;
  685.         procNum.lowLongOfPSN := kNoProcess;
  686.  
  687.         (* Keep looping through each open process *)
  688.         WHILE GetNextProcess ((*◊*)procNum) = noErr DO
  689.             BEGIN
  690.                 (* Get information about an open process *)
  691.                 procInfo.processInfoLength := SIZEOF (ProcessInfoRec);
  692.                 procInfo.processName := @procName;
  693.                 procInfo.processAppSpec := NIL;
  694.                 error := GetProcessInformation (procNum, (*◊*)procInfo);
  695.  
  696.                 (* Cmp List Mgr & Proc Mgr lists if enuf cells for # of processes *)
  697.                 IF PtInRect (currCell, procList^^.dataBounds) THEN
  698.                     BEGIN
  699.                         (* Get process info from List Mgr list *)
  700.                         listInfoLength := SIZEOF (ProcessListInfoRec);
  701.                         LGetCell ((*<*)@listInfo, (*◊*)listInfoLength, currCell,
  702.                                 procList);
  703.  
  704.                         (* If Proc & List Mgr lists differ, update List Mgr list *)
  705.                         error := SameProcess (procInfo.processNumber, listInfo.
  706.                                 serialNumber, (*<*)equal);
  707.                         IF NOT equal THEN
  708.                             BEGIN
  709.                                 (* See if matching process farther down List Mgr list *)
  710.                                 matchCell := currCell;
  711.                                 foundMatch := LSearch (@procInfo.processNumber,
  712.                                         SIZEOF (ProcessSerialNumber), gEqualPSNUPP,
  713.                                         (*◊*)matchCell, procList);
  714.  
  715.                                 (* Was there a match farther down the List Mgr list? *)
  716.                                 IF foundMatch THEN
  717.                                     (* Yes, delete intervening cells *)
  718.                                     LDelRow (matchCell.v - currCell.v, currCell.v,
  719.                                             procList)
  720.                                 ELSE
  721.                                     (* No, insert the new process into List Mgr list *)
  722.                                     BEGIN
  723.                                         currCell.v := LAddRow (1, currCell.v, procList);
  724.                                         SetProcessListInfo (procInfo, currCell.v,
  725.                                                 procList)
  726.                                     END
  727.                             END
  728.                     END
  729.                 ELSE
  730.                     BEGIN
  731.                         (* Ran out of rows, add one *)
  732.                         currCell.v := LAddRow (1, currCell.v, procList);
  733.                         addedProcess := TRUE;
  734.  
  735.                         (* Set the new row to the new process information *)
  736.                         SetProcessListInfo (procInfo, currCell.v, procList)
  737.                     END;
  738.  
  739.                 (* Go to the next cell element in List Mgr list *)
  740.                 currCell.v := SUCC (currCell.v)
  741.             END;
  742.  
  743.         (* Delete any extraneous cells *)
  744.         IF currCell.v < procList^^.dataBounds.bottom THEN
  745.             LDelRow (procList^^.dataBounds.bottom - currCell.v, currCell.v,
  746.                     procList);
  747.  
  748.         (* If added processes to the list and memory low, warn *)
  749.         IF addedProcess AND FailLowMemory (0) THEN
  750.             junkError := ShowCautionOKAlert (rMemErrMessages, kMemErrLowMemWarnMsg, junkItemHit)
  751.     END;
  752.  
  753.  
  754. {$S ProcessGuts}
  755. (*******************************************************************************
  756. * Public: DrawProcessListWindow
  757. *
  758. * Not much here to explain.
  759. *******************************************************************************)
  760.  
  761.     PROCEDURE DrawProcessListWindow (processListWindow: WindowPtr);
  762.  
  763.         VAR
  764.             procList: ListHandle; {Handle to List Mgr process list}
  765.  
  766.     BEGIN
  767.         SetPort (processListWindow);
  768.  
  769.         (* Get the List Manager’s copy of the process list *)
  770.         procList := ListHandle(GetWRefCon (processListWindow));
  771.  
  772.         (* Update the list *)
  773.         TextFont (applFont);
  774.         TextFace ([]);
  775.         TextSize (GetDefFontSize);
  776.         EraseRect (processListWindow^.portRect);
  777.         LUpdate (processListWindow^.visRgn, procList);
  778.     END;
  779.  
  780.  
  781. {$S ProcessGuts}
  782. (*******************************************************************************
  783. * Public: ClickProcessListWindow
  784. *
  785. * The List Manager is doing the lion’s share of the work.
  786. *******************************************************************************)
  787.  
  788.     PROCEDURE ClickProcessListWindow (processListWindow: WindowPtr;
  789.                                       clickEvent:        EventRecord);
  790.  
  791.         VAR
  792.             procList:    ListHandle; {Handle to List Mgr process list}
  793.             clickPos:    Point;      {Position of mouse click in window coords}
  794.             doubleClick: Boolean;    {TRUE if cell was double-clicked}
  795.  
  796.     BEGIN
  797.         SetPort (processListWindow);
  798.  
  799.         (* Get the List Manager’s copy of the process list *)
  800.         procList := ListHandle(GetWRefCon (processListWindow));
  801.  
  802.         (* Call the List Manager to handle the click *)
  803.         clickPos := clickEvent.where;
  804.         GlobalToLocal ((*◊*)clickPos);
  805.         doubleClick := LClick (clickPos, clickEvent.modifiers, procList);
  806.         IF doubleClick THEN
  807.             DoBringProcessToFront (processListWindow);
  808.     END;
  809.  
  810.  
  811. {$S ProcessGuts}
  812. (*******************************************************************************
  813. * Public: ActivateProcessListWindow
  814. *
  815. * The List Manager is called to activate/deactivate the process list window.
  816. *******************************************************************************)
  817.  
  818.     PROCEDURE ActivateProcessListWindow (processListWindow: WindowPtr;
  819.                                          becomingActive:    Boolean);
  820.  
  821.         VAR
  822.             procList: ListHandle; {Handle to List Mgr process list}
  823.  
  824.     BEGIN
  825.         SetPort (processListWindow);
  826.  
  827.         (* Get the List Manager’s copy of the process list *)
  828.         procList := ListHandle(GetWRefCon (processListWindow));
  829.  
  830.         (* Call the List Manager to activate or deactivate the list *)
  831.         LActivate (becomingActive, procList)
  832.     END;
  833.  
  834.  
  835. {$S ProcessGuts}
  836. (*******************************************************************************
  837. * Public: FixProcessListMenus
  838. *
  839. * The three launching items in the File menu are enabled as long as there’s
  840. * enough memory available.
  841. *
  842. * The List Manager routine, LGetSelect, is called to see if there are any
  843. * processes in the Process List window specified by the "processListWindow"
  844. * parameter that are selected.  If there are, then the three items in the
  845. * Process menu are enabled.  If there isn’t enough memory to safely work in,
  846. * then only the Bring Process to Front is enabled.
  847. *******************************************************************************)
  848.  
  849.     PROCEDURE FixProcessListMenus (processListWindow: WindowPtr);
  850.  
  851.         CONST
  852.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  853.  
  854.         VAR
  855.             aMenu:    MenuHandle; {Handle to any menu we’re checking on}
  856.             procList: ListHandle; {Handle to List Mgr process list}
  857.             aCell:    Cell;       {Cell of process list}
  858.  
  859.     BEGIN
  860.         (* Get the List Manager’s copy of the process list *)
  861.         procList := ListHandle(GetWRefCon (processListWindow));
  862.  
  863.         (* Enable the File menu launch items *)
  864.         aMenu := GetMenuHandle (mFile);
  865.         IF NOT FailLowMemory (0) THEN
  866.             BEGIN
  867.                 EnableItem (aMenu, iLaunchFore);
  868.                 EnableItem (aMenu, iLaunchBack);
  869.                 EnableItem (aMenu, iLaunchTo)
  870.             END;
  871.  
  872.         (* Undim the Process menu items *)
  873.         aMenu := GetMenuHandle (mProcess);
  874.         aCell.v := 0;
  875.         aCell.h := 0;
  876.         IF LGetSelect (kFindNext, (*◊*)aCell, procList) THEN
  877.             BEGIN
  878.                 (* There’s ≥ 1 sel’d process, enable Bring Process to Front *)
  879.                 EnableItem (aMenu, iBringFront);
  880.  
  881.                 (* Only enable other two items if enough memory to safely work *)
  882.                 IF NOT FailLowMemory (0) THEN
  883.                     BEGIN
  884.                         EnableItem (aMenu, iShowProcessInfo);
  885.                         EnableItem (aMenu, iTerminateProcess)
  886.                     END
  887.             END
  888.     END;
  889.  
  890.  
  891. {$S Main}
  892. (*******************************************************************************
  893. * Public: IsProcessInfoWindow
  894. *
  895. * I store a unique code in the windowKind field of every window I create so that
  896. * I can identify the kind of window it is later… like now!  I check to see if
  897. * the windowKind field of aWindow is kProcessInfoWindKind or not.  If it is, I
  898. * know it’s a process info window, and so IsProcessInfoWindow returns TRUE.
  899. *******************************************************************************)
  900.  
  901.     FUNCTION IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
  902.  
  903.     BEGIN
  904.         IF aWindow <> NIL THEN
  905.             IsProcessInfoWindow := WindowPeek(aWindow)^.windowKind =
  906.                     kProcessInfoWindKind
  907.         ELSE
  908.             IsProcessInfoWindow := FALSE
  909.     END;
  910.  
  911.  
  912. {$S ProcessGuts}
  913. (*******************************************************************************
  914. * Private: GetNumberParts - Get the default number parts table
  915. *
  916. * To use the Script Manager’s number conversion routines, the number parts table
  917. * in the 'itl4' resource must be retrieved.  This routine gets the itl4 resource
  918. * and copies the number parts table into the "partsTable" parameter.
  919. *
  920. * If the retrieval was successful, then TRUE is returned.  If the itl4 resource
  921. * couldn’t be loaded for some reason, then FALSE is returned.
  922. *******************************************************************************)
  923.  
  924.     FUNCTION GetNumberParts (VAR partsTable: NumberParts): Boolean;
  925.  
  926.         VAR
  927.             intl4: Itl4Handle; {Handle to the itl4 resource}
  928.  
  929.     BEGIN
  930.         intl4 := Itl4Handle(GetIntlResource (4));
  931.         IF intl4 <> NIL THEN
  932.             BEGIN
  933.                 partsTable := NumberPartsPtr(ORD (intl4^) + intl4^^.
  934.                         defPartsOffset)^;
  935.                 GetNumberParts := TRUE
  936.             END
  937.         ELSE
  938.             GetNumberParts := FALSE
  939.     END;
  940.  
  941.  
  942. {$S ProcessGuts}
  943. (*******************************************************************************
  944. * Private: TextLineBox - Draw a line of text into a box.
  945. *
  946. * This routine is very similar to TextEdit’s TETextBox routine, and in fact it
  947. * takes the same parameters.  But TextLineBox draws a single line of text
  948. * specified by "textLine" and having the length specified by "length" into
  949. * the current GrafPort, ignoring carriage returns and word-wrap.  This means
  950. * that there’s less overhead than TETextBox.  But TETextBox itself is optimized for
  951. * single lines of text, so there is an ulterior motive for this routine.
  952. * TETextBox erases the entire box before drawing the text.  This results in a
  953. * slight flicker if TETextBox is called to draw over previous text.  TextLineBox
  954. * only erases the part of the box that isn’t covered with the text specified by
  955. * "textLine".  Also, the text is drawn in srcCopy mode.  If TextLineBox is
  956. * called to draw over existing text, the result should be a smooth transition
  957. * from one text to another, without flicker.
  958. *******************************************************************************)
  959.  
  960.     PROCEDURE TextLineBox (textLine: Ptr;
  961.                            length:   Integer;
  962.                            box:      Rect;
  963.                            just:     Integer);
  964.  
  965.         VAR
  966.             currPort:     GrafPtr;   {Pointer to the current GrafPort}
  967.             currTextMode: Integer;   {Current text mode}
  968.             currFont:     FontInfo;  {Current font information}
  969.             lineWidth:    Integer;   {Width of line of text in pixels}
  970.             spareSpace:   Integer;   {Width of box - width of text}
  971.             spareRect:    Rect;      {Rectangle of area not filled with text}
  972.             currClip:     RgnHandle; {Handle to the current clip region}
  973.  
  974.     BEGIN
  975.         (* Save the current clip region and set the clip region to "box" *)
  976.         currClip := NewRgn;
  977.         GetClip ((*<*)currClip);
  978.         ClipRect (box);
  979.  
  980.         (* Save the current text mode and set it to srcCopy *)
  981.         GetPort ((*<*)currPort);
  982.         currTextMode := currPort^.txMode;
  983.         TextMode (srcCopy);
  984.  
  985.         (* If default justification, set to real justification based on SysJust *)
  986.         IF just = teFlushDefault THEN
  987.             IF GetSysDirection = 0 THEN
  988.                 just := teFlushLeft
  989.             ELSE
  990.                 just := teFlushRight;
  991.  
  992.         (* Move pen to baseline on left side of box *)
  993.         GetFontInfo (currFont);
  994.         MoveTo (box.left, box.top + currFont.ascent);
  995.  
  996.         (* Find the width of the specified text *)
  997.         lineWidth := TextWidth (textLine, 0, length);
  998.  
  999.         (* Adjust the pen for centered or right-aligned text *)
  1000.         IF just <> teFlushLeft THEN
  1001.             BEGIN
  1002.                 spareSpace := box.right - box.left - lineWidth;
  1003.                 IF just = teCenter THEN
  1004.                     spareSpace := spareSpace DIV 2;
  1005.                 Move (spareSpace, 0);
  1006.             END;
  1007.  
  1008.         (* Erase area at end(s) of text *)
  1009.         spareRect := box;
  1010.         IF just = teFlushLeft THEN
  1011.             spareRect.left := spareRect.left + lineWidth
  1012.         ELSE
  1013.             BEGIN
  1014.                 IF just = teCenter THEN
  1015.                     BEGIN
  1016.                         spareRect.left := spareRect.left + spareSpace + lineWidth;
  1017.                         EraseRect (spareRect)
  1018.                     END;
  1019.                 spareRect.left := box.left;
  1020.                 spareRect.right := spareRect.left + spareSpace;
  1021.             END;
  1022.         IF NOT EmptyRect (spareRect) THEN
  1023.             EraseRect (spareRect);
  1024.  
  1025.         (* Draw the line of text *)
  1026.         DrawText (textLine, 0, length);
  1027.  
  1028.         (* Restore the port to its normal state *)
  1029.         TextMode (currTextMode);
  1030.         SetClip (currClip);
  1031.         DisposeRgn (currClip)
  1032.     END;
  1033.  
  1034.  
  1035. {$S ProcessGuts}
  1036. (*******************************************************************************
  1037. * Private: FindProcessInfoWindow - Find a process info window for a process
  1038. *
  1039. * This routine searches the window list for a process info window that
  1040. * represents the process with the process serial number specified by
  1041. * "searchPSN".  Every process info window has a handle to the process serial
  1042. * number of the process it represents in the refCon field of the window.  The
  1043. * Process Manager routine, SameProcess, does the work of comparing the given
  1044. * process serial number against the process serial number in the refCon.
  1045. *
  1046. * If a window for the specified process is found, a pointer to that window is
  1047. * returned.  If there isn’t any window representing the given process, then NIL
  1048. * is returned.
  1049. *******************************************************************************)
  1050.  
  1051.     FUNCTION FindProcessInfoWindow (searchPSN: ProcessSerialNumber): WindowPtr;
  1052.  
  1053.         VAR
  1054.             testWindow: WindowPtr; {Pointer to window we’re testing}
  1055.             found:      Boolean;   {TRUE if matching process info window was found}
  1056.             psnHandle:  Handle;    {Handle to PSN of window’s process info window}
  1057.             error:      OSErr;
  1058.  
  1059.     BEGIN
  1060.         found := FALSE;
  1061.         testWindow := FrontWindow;
  1062.  
  1063.         (* Loop until the window is found or every window has been searched *)
  1064.         WHILE (testWindow <> NIL) AND (NOT found) DO
  1065.             BEGIN
  1066.                 IF IsProcessInfoWindow (testWindow) THEN
  1067.                     BEGIN
  1068.                         (* Get the PSN of the window from its refCon *)
  1069.                         psnHandle := Handle(GetWRefCon (testWindow));
  1070.  
  1071.                         (* Compare window’s PSN against searchPSN *)
  1072.                         HLock (psnHandle);
  1073.                         error := SameProcess (searchPSN, ProcessSerialNumberPtr(psnHandle^)^,
  1074.                                 (*<*)found);
  1075.                         HUnlock (psnHandle)
  1076.                     END;
  1077.  
  1078.                 (* Go to the next window in the window list *)
  1079.                 IF NOT found THEN
  1080.                     testWindow := WindowPtr(WindowPeek(testWindow)^.nextWindow)
  1081.             END;
  1082.  
  1083.         (* Return pointer to matching process info window, or NIL if no match *)
  1084.         FindProcessInfoWindow := testWindow
  1085.     END;
  1086.  
  1087.  
  1088. {$S ProcessGuts}
  1089. (*******************************************************************************
  1090. * Private: CloseProcessInfoWindow - Close a process info window
  1091. *
  1092. * The process info window specified by "processInfoWindow" is closed and all its
  1093. * associated memory is deallocated.
  1094. *******************************************************************************)
  1095.  
  1096.     PROCEDURE CloseProcessInfoWindow (processInfoWindow: WindowPtr);
  1097.  
  1098.     BEGIN
  1099.         DisposeHandle (Handle(GetWRefCon (processInfoWindow)));
  1100.         CloseWindow (processInfoWindow);
  1101.         DisposeDialogItems (processInfoWindow);
  1102.         DisposePtr (Ptr(processInfoWindow))
  1103.     END;
  1104.  
  1105.  
  1106. {$S ProcessGuts}
  1107. (*******************************************************************************
  1108. * Private: CreateProcessInfoWindow - Create a process info window
  1109. *
  1110. * This routine is called to create a new process info window and to display it
  1111. * on the screen.  A pointer to the window is returned.  If there wasn’t enough
  1112. * memory to open the new window, or if there was some other problem preventing
  1113. * the window from being completely created, then an alert indicating the problem
  1114. * is presented to the user and NIL is returned.
  1115. *
  1116. * I store the constant kProcessInfoWindKind into the windowKind field of the new
  1117. * window.  When the routine IsProcessInfoWindow is called, it uses this field to
  1118. * identify a window as a process info window.
  1119. *******************************************************************************)
  1120.  
  1121.     FUNCTION CreateProcessInfoWindow: WindowPtr;
  1122.  
  1123.         VAR
  1124.             aWindow: WindowPtr; {Pointer to the new window}
  1125.             error:   OSErr;
  1126.  
  1127.         PROCEDURE HandleError (messageClass: Integer;
  1128.                                messageIndex: Integer);
  1129.  
  1130.             VAR
  1131.                 junkError: OSErr;
  1132.                 junkItemHit: Integer; {Result of alert; ignored}
  1133.  
  1134.         BEGIN
  1135.             IF aWindow <> NIL THEN
  1136.                 CloseProcessInfoWindow (aWindow);
  1137.             junkError := ShowStopAlert (messageClass, messageIndex, junkItemHit);
  1138.             gError := noErr;
  1139.             CreateProcessInfoWindow := NIL;
  1140.             EXIT (CreateProcessInfoWindow)
  1141.         END;
  1142.  
  1143.     BEGIN
  1144.         aWindow := NIL;
  1145.  
  1146.         (* Create the new window *)
  1147.         aWindow := CreateDialog (rProcessInfoWindID);
  1148.         IF aWindow = NIL THEN
  1149.             IF gError = memFullErr THEN
  1150.                 HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
  1151.             ELSE IF gError = resNotFound THEN
  1152.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  1153.             ELSE IF gError = dsSysErr THEN
  1154.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  1155.  
  1156.         (* Set up the window *)
  1157.         SetPort (aWindow);
  1158.         WindowPeek(aWindow)^.windowKind := kProcessInfoWindKind;
  1159.  
  1160.         (* Install the dialog items *)
  1161.         error := InstallDialogItems (aWindow, rProcessInfoDitlID);
  1162.         IF error <> noErr THEN
  1163.             IF error = memFullErr THEN
  1164.                 HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
  1165.             ELSE IF error = resNotFound THEN
  1166.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  1167.             ELSE IF error = dsSysErr THEN
  1168.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  1169.  
  1170.         CreateProcessInfoWindow := aWindow
  1171.     END;
  1172.  
  1173.  
  1174. {$S ProcessGuts}
  1175. (*******************************************************************************
  1176. * Private: DrawGrayLine - Draw a gray line into a dialog item
  1177. *
  1178. * DrawGrayLine draws a line from the top-left corner of "grayLineRect" to its
  1179. * bottom-right corner.  On a non-Color QuickDraw Macintosh, this line is simply
  1180. * drawn using the 50% gray pattern.  On a Color QuickDraw Macintosh, a gray
  1181. * type-2 pattern is created with a gray color.  When this pattern is used to
  1182. * draw to the screen, it is drawn using the specified color if possible.  If
  1183. * there aren’t enough available colors, the color is dithered using the closest
  1184. * available colors.
  1185. *******************************************************************************)
  1186.  
  1187.     PROCEDURE DrawGrayLine (grayLineRect: Rect);
  1188.  
  1189.         VAR
  1190.             grayColor:   RGBColor;     {Color of gray line}
  1191.             grayPattern: PixPatHandle; {Handle to the gray pattern}
  1192.  
  1193.     BEGIN
  1194.         grayPattern := NIL;
  1195.         PenNormal;
  1196.  
  1197.         (* See if Color QuickDraw is on this machine or not *)
  1198.         IF NOT HasColourQuickDraw THEN
  1199.             (* Nope, just draw a 50% gray pattern *)
  1200.             PenPat (qd.gray)
  1201.         ELSE
  1202.             (* Yup, make a true gray pattern that can be dithered to the screen *)
  1203.             BEGIN
  1204.                 grayColor.red := $7FFF;
  1205.                 grayColor.green := $7FFF;
  1206.                 grayColor.blue := $7FFF;
  1207.                 grayPattern := NewPixPat;
  1208.                 MakeRGBPat (grayPattern, grayColor);
  1209.                 PenPixPat (grayPattern);
  1210.             END;
  1211.  
  1212.         (* Draw the line *)
  1213.         MoveTo (grayLineRect.left, grayLineRect.top);
  1214.         LineTo (grayLineRect.right, grayLineRect.bottom);
  1215.  
  1216.         (* Clean up *)
  1217.         IF grayPattern <> NIL THEN
  1218.             DisposePixPat (grayPattern);
  1219.         PenNormal
  1220.     END;
  1221.  
  1222. {$S ProcessGuts}
  1223. (*******************************************************************************
  1224. * Private: MyNumberString - Converts a number to an international friendly string
  1225. *
  1226. * Numbers are converted to strings using the ExtendedToString routine.  ExtendedToString
  1227. * requires a script-independent canonical number format so that the resulting
  1228. * string appears with the proper thousands separator regardless of the script
  1229. * in use.  I previously created a canonical number format that has the form
  1230. * ###,###,### in the U.S and saved it in a resource of type 'FMAT'.
  1231. *
  1232. * You can even use Michael Hecht's way cool 'FMAT' editor to play with this
  1233. * resource in ResEdit.  Get it from:
  1234.  
  1235.   <ftp://mirror.apple.com/mirrors/mac.archive.umich.edu/util/developer/
  1236.     fmateditor1.01.sit.hqx>
  1237. *******************************************************************************)
  1238.     PROCEDURE MyNumberString(number: LongInt; VAR numberStr: Str255);
  1239.         VAR
  1240.             partsTable:   NumberParts;      {Number parts table from itl4 resource}
  1241.             canonRsrc:    Handle;           {Hnd to canonical # format '###,###,###'}
  1242.             numberAsDouble:Double;            {for use with dtox80}
  1243.             numberAsExtended80:extended80;    {for use with ExtendedToString}
  1244.             success:       Boolean;          {TRUE if GetNumberParts call worked}
  1245.             status:        FormatStatus;    {Status of #->String conversion}
  1246.     BEGIN
  1247.         (* Starting here, convert number to a string *)
  1248.         numberAsDouble := number;
  1249.         {$ifc GENERATINGCFM}
  1250.             dtox80(numberAsDouble, numberAsExtended80);
  1251.         {$elsec}
  1252.             numberAsExtended80 := numberAsDouble;
  1253.         {$endc}
  1254.  
  1255.         (* Get number parts table from itl4 *)
  1256.         success := GetNumberParts ((*<*)partsTable);
  1257.         IF success THEN
  1258.             BEGIN
  1259.                 (* Get my canonical number format *)
  1260.                 canonRsrc := Get1Resource ('FMAT', 128);
  1261.                 IF canonRsrc <> NIL THEN
  1262.                     BEGIN
  1263.                         (* Convert free space to equivalent string *)
  1264.                         HLock (canonRsrc);
  1265.                         status := ExtendedToString (numberAsExtended80,
  1266.                                 NumFormatStringPtr(canonRsrc^)^, partsTable,
  1267.                                 (*<*)numberStr);
  1268.                         HUnlock (canonRsrc);
  1269.  
  1270.                     END;
  1271.             END;
  1272.     END;
  1273.  
  1274. {$S ProcessGuts}
  1275. (*******************************************************************************
  1276. * Private: SetUpProcessInfoItems - Set up process information static text items
  1277. *
  1278. * This routine sets up the text of the static text items in the process info
  1279. * window specified by "processInfoWindow" to reflect the process information
  1280. * passed in the "processInfo" parameter.  Only the process information that
  1281. * doesn’t change while a process is active is set in this routine.  Information
  1282. * that changes while a process is active is set and drawn in the
  1283. * IdleProcessInfoWindow routine.
  1284. *******************************************************************************)
  1285.  
  1286.     PROCEDURE SetUpProcessInfoItems (processInfoWindow: WindowPtr;
  1287.                                      processInfo:       ProcessInfoRec);
  1288.  
  1289.         VAR
  1290.             itemString:    Str255;       {"Application" or "Desk Accessory" string}
  1291.             blankString:   Integer;      {Dummy empty string}
  1292.             checkString:   StringPtr;    {Ptr either to check mark or blankString}
  1293.             checkStrHnd:   StringHandle; {Handle to check mark string}
  1294.  
  1295.     BEGIN
  1296.         (* Set process name *)
  1297.         SetStatTextItem (processInfoWindow, kProcessNameItem, @processInfo.
  1298.                 processName^ [1], ORD (processInfo.processName^ [0]));
  1299.  
  1300.         (* Set Application or Desk Accessory string *)
  1301.         IF BAND (processInfo.processMode, modeDeskAccessory) <> 0 THEN
  1302.             GetIndString ((*◊*)itemString, rAppOrDAStringID, kDAStringInd)
  1303.         ELSE
  1304.             GetIndString ((*◊*)itemString, rAppOrDAStringID, kAppStringInd);
  1305.         SetStatTextItem (processInfoWindow, kAppOrDAItem, @itemString [1],
  1306.                 ORD (itemString [0]));
  1307.  
  1308.         (* Set partition size item *)
  1309.         MyNumberString(processInfo.processSize DIV 1024, itemString);
  1310.  
  1311.         SetStatTextItem (processInfoWindow, kTotalSizeItem,
  1312.                 @itemString [1], ORD (itemString [0]));
  1313.  
  1314.         (* Set type and creator *)
  1315.         SetStatTextItem (processInfoWindow, kTypeItem, @processInfo.processType,
  1316.                 SIZEOF (LongInt));
  1317.         SetStatTextItem (processInfoWindow, kCreatorItem, @processInfo.
  1318.                 processSignature, SIZEOF (OSType));
  1319.  
  1320.         (* Initialize the checkmark and blank strings *)
  1321.         checkStrHnd := GetString (rCheckMarkID);
  1322.         IF checkStrHnd <> NIL THEN
  1323.             BlockMoveData (Ptr(checkStrHnd^), @itemString, ORD (checkStrHnd^^ [0]) + 1)
  1324.         ELSE
  1325.             itemString [0] := CHR (0);
  1326.         blankString := 0;
  1327.  
  1328.         (* Check the suspend/resume flag *)
  1329.         IF BAND (processInfo.processMode, modeNeedSuspendResume) <> 0 THEN
  1330.             checkString := @itemString
  1331.         ELSE
  1332.             checkString := @blankString;
  1333.         SetStatTextItem (processInfoWindow, kSusResChkItem, @checkString^ [1],
  1334.                 ORD (checkString^ [0]));
  1335.  
  1336.         (* Check the window activate flag *)
  1337.         IF BAND (processInfo.processMode, modeDoesActivateOnFGSwitch) <> 0 THEN
  1338.             checkString := @itemString
  1339.         ELSE
  1340.             checkString := @blankString;
  1341.         SetStatTextItem (processInfoWindow, kWindActChkItem, @checkString^ [1],
  1342.                 ORD (checkString^ [0]));
  1343.  
  1344.         (* Check the front clicks flag *)
  1345.         IF BAND (processInfo.processMode, modeGetFrontClicks) <> 0 THEN
  1346.             checkString := @itemString
  1347.         ELSE
  1348.             checkString := @blankString;
  1349.         SetStatTextItem (processInfoWindow, kGetClickChkItem, @checkString^ [1],
  1350.                 ORD (checkString^ [0]));
  1351.  
  1352.         (* Check the application-died event flag *)
  1353.         IF BAND (processInfo.processMode, modeGetAppDiedMsg) <> 0 THEN
  1354.             checkString := @itemString
  1355.         ELSE
  1356.             checkString := @blankString;
  1357.         SetStatTextItem (processInfoWindow, kAppDiedChkItem, @checkString^ [1],
  1358.                 ORD (checkString^ [0]));
  1359.  
  1360.         (* Check the stationery flag *)
  1361.         IF BAND (processInfo.processMode, modeStationeryAware) <> 0 THEN
  1362.             checkString := @itemString
  1363.         ELSE
  1364.             checkString := @blankString;
  1365.         SetStatTextItem (processInfoWindow, kStationeryChkItem, @checkString^ [1],
  1366.                 ORD (checkString^ [0]));
  1367.  
  1368.         (* Check the can background flag *)
  1369.         IF BAND (processInfo.processMode, modeCanBackground) <> 0 THEN
  1370.             checkString := @itemString
  1371.         ELSE
  1372.             checkString := @blankString;
  1373.         SetStatTextItem (processInfoWindow, kCanBackChkItem, @checkString^ [1],
  1374.                 ORD (checkString^ [0]));
  1375.  
  1376.         (* Check the background only flag *)
  1377.         IF BAND (processInfo.processMode, modeOnlyBackground) <> 0 THEN
  1378.             checkString := @itemString
  1379.         ELSE
  1380.             checkString := @blankString;
  1381.         SetStatTextItem (processInfoWindow, kOnlyBackChkItem, @checkString^ [1],
  1382.                 ORD (checkString^ [0]));
  1383.  
  1384.         (* Check the high-level event aware flag *)
  1385.         IF BAND (processInfo.processMode, modeHighLevelEventAware) <> 0 THEN
  1386.             checkString := @itemString
  1387.         ELSE
  1388.             checkString := @blankString;
  1389.         SetStatTextItem (processInfoWindow, kHighLevelChkItem, @checkString^ [1],
  1390.                 ORD (checkString^ [0]));
  1391.  
  1392.         (* Check the local and remote high-level event flag *)
  1393.         IF BAND (processInfo.processMode, modeLocalAndRemoteHLEvents) <> 0 THEN
  1394.             checkString := @itemString
  1395.         ELSE
  1396.             checkString := @blankString;
  1397.         SetStatTextItem (processInfoWindow, kRHighLevelChkItem, @checkString^ [1],
  1398.                 ORD (checkString^ [0]));
  1399.  
  1400.         (* Check the multiple launch flag *)
  1401.         IF BAND (processInfo.processMode, modeMultiLaunch) <> 0 THEN
  1402.             checkString := @itemString
  1403.         ELSE
  1404.             checkString := @blankString;
  1405.         SetStatTextItem (processInfoWindow, kMultiUserChkItem, @checkString^ [1],
  1406.                 ORD (checkString^ [0]));
  1407.  
  1408.         (* Check the 32-bit clean flag *)
  1409.         IF BAND (processInfo.processMode, mode32BitCompatible) <> 0 THEN
  1410.             checkString := @itemString
  1411.         ELSE
  1412.             checkString := @blankString;
  1413.         SetStatTextItem (processInfoWindow, k32BitCleanChkItem, @checkString^ [1],
  1414.                 ORD (checkString^ [0]));
  1415.  
  1416.         (* Check the use TextEdit services flag *)
  1417.         IF BAND (processInfo.processMode, modeUseTextEditServices) <> 0 THEN
  1418.             checkString := @itemString
  1419.         ELSE
  1420.             checkString := @blankString;
  1421.         SetStatTextItem (processInfoWindow, kUseTextEditServicesChkItem, @checkString^ [1],
  1422.                 ORD (checkString^ [0]));
  1423.  
  1424.         (* Check the Display Manager aware flag *)
  1425.         IF BAND (processInfo.processMode, modeDisplayManagerAware) <> 0 THEN
  1426.             checkString := @itemString
  1427.         ELSE
  1428.             checkString := @blankString;
  1429.         SetStatTextItem (processInfoWindow, kDisplayManagerAwareChkItem, @checkString^ [1],
  1430.                 ORD (checkString^ [0]));
  1431.  
  1432.     END;
  1433.  
  1434.  
  1435. {$S ProcessGuts}
  1436. (*******************************************************************************
  1437. * Public: IdleProcessInfoWindow
  1438. *
  1439. * The memory indicator and the free memory readout are updated with the current
  1440. * values.
  1441. *
  1442. * The free memory readout is a static text item in the DITL, but there’s no text
  1443. * for it.  Instead, I’m drawing into that item’s rectangle using TextLineBox.
  1444. * I set the item up as a static text item just so that I can specify the type
  1445. * characteristics of the free memory readout from the DITL resource rather than
  1446. * hard-coding them in this routine.
  1447. *******************************************************************************)
  1448.  
  1449.     PROCEDURE IdleProcessInfoWindow (processInfoWindow: WindowPtr);
  1450.  
  1451.         VAR
  1452.             processInfo:   ProcessInfoRec; {Process info for window’s process}
  1453.             psnHandle:     Handle;         {Handle to PSN of window’s process}
  1454.             freeAngle:     Integer;        {Angle between free and full memory}
  1455.             error:         OSErr;
  1456.             itemRect:      Rect;           {Rectangle of dialog item}
  1457.             itemType:     TypeInfoRec;     {Type information for free mem readout}
  1458.             freeSpaceStr:  Str255;           {Free space in process, as string}
  1459.             
  1460.     BEGIN
  1461.         SetPort (processInfoWindow);
  1462.         PenNormal;
  1463.  
  1464.         (* Get the PSN of the process associated with processInfoWindow *)
  1465.         psnHandle := Handle(GetWRefCon (processInfoWindow));
  1466.  
  1467.         (* Get information about an open process *)
  1468.         processInfo.processInfoLength := SIZEOF (ProcessInfoRec);
  1469.         processInfo.processName := NIL;
  1470.         processInfo.processAppSpec := NIL;
  1471.         HLock (psnHandle);
  1472.         error := GetProcessInformation (ProcessSerialNumberPtr(psnHandle^)^, (*◊*)processInfo);
  1473.         HUnlock (psnHandle);
  1474.  
  1475.         (* Check to see whether the process still exists *)
  1476.         IF error = procNotFound THEN
  1477.             (* Process terminated, so close this process info window *)
  1478.             CloseProcessInfoWindow (processInfoWindow)
  1479.         ELSE
  1480.             BEGIN
  1481.                 (* Starting here, convert amount of free space to a string *)
  1482.                 MyNumberString(processInfo.processFreeMem DIV 1024, freeSpaceStr);
  1483.  
  1484.                 (* Get the item rectangle of the free-space readout *)
  1485.                 GetDialogItemRect (processInfoWindow, kFreeSpaceItem, (*<*)itemRect);
  1486.  
  1487.                 (* Get the font characteristics of the stat text item *)
  1488.                 GetStatTextFontInfo (processInfoWindow, kFreeSpaceItem, (*<*)itemType);
  1489.  
  1490.                 (* Draw the free-space readout *)
  1491.                 TextFont (itemType.typeFace);
  1492.                 TextSize (itemType.typeSize);
  1493.                 TextFace (itemType.typeStyle);
  1494.                 TextLineBox (@freeSpaceStr [1], ORD (freeSpaceStr [0]),
  1495.                         itemRect, itemType.textJust);
  1496.  
  1497.                 (* Draw the memory indicator frame *)
  1498.                 GetDialogItemRect (processInfoWindow, kMemIndicatorItem,
  1499.                         (*<*)itemRect);
  1500.                 FrameOval (itemRect);
  1501.                 InsetRect ((*◊*)itemRect, 1, 1);
  1502.  
  1503.                 (* Calc angle in the memory indicator that the free memory begins *)
  1504.                 freeAngle := processInfo.processFreeMem * 360 DIV processInfo.
  1505.                         processSize;
  1506.  
  1507.                 (* Draw the memory indicator *)
  1508.                 IF NOT HasColourQuickDraw THEN
  1509.                     PenPat (qd.black)
  1510.                 ELSE
  1511.                     BEGIN
  1512.                         PmForeColor (kUsedColor);
  1513.                         PmBackColor (0)
  1514.                     END;
  1515.  
  1516.                 (* Draw the used memory part of the memory indicator *)
  1517.                 PaintArc (itemRect, 0, 360 - freeAngle);
  1518.  
  1519.                 (* Set the color of the free memory part of the indicator *)
  1520.                 IF NOT HasColourQuickDraw THEN
  1521.                     PenPat (qd.white)
  1522.                 ELSE
  1523.                     BEGIN
  1524.                         PmForeColor (kFreeColor);
  1525.                         PmBackColor (1)
  1526.                     END;
  1527.  
  1528.                 (* Draw the free memory part of the memory indicator *)
  1529.                 PaintArc (itemRect, 360 - freeAngle, freeAngle);
  1530.  
  1531.                 (* Reset the port characteristics back to normal *)
  1532.                 PenNormal;
  1533.                 IF HasColourQuickDraw THEN
  1534.                     BEGIN
  1535.                         PmForeColor (1);
  1536.                         PmBackColor (0)
  1537.                     END
  1538.             END
  1539.     END;
  1540.  
  1541.  
  1542. {$S ProcessGuts}
  1543. (*******************************************************************************
  1544. * Public: DrawProcessInfoWindow
  1545. *
  1546. * The Dialog Utility routine, DrawDialogItems, is called to draw all the
  1547. * standard dialog items in the processInfoWindow specified by processInfoWindow.
  1548. * Then, the cosmetic gray lines are drawn.  The memory readouts aren’t drawn
  1549. * because they’re drawn in IdleProcessInfoWindow.
  1550. *******************************************************************************)
  1551.  
  1552.     PROCEDURE DrawProcessInfoWindow (processInfoWindow: WindowPtr);
  1553.  
  1554.         VAR
  1555.             grayLineRect: Rect; {Rectangle of gray line item}
  1556.  
  1557.     BEGIN
  1558.         (* Draw the standard dialog items *)
  1559.         DrawDialogItems (processInfoWindow);
  1560.  
  1561.         (* Draw the two gray, cosmetic, separating lines *)
  1562.         GetDialogItemRect (processInfoWindow, kGrayLineItem0, (*<*)grayLineRect);
  1563.         DrawGrayLine (grayLineRect);
  1564.         GetDialogItemRect (processInfoWindow, kGrayLineItem1, (*<*)grayLineRect);
  1565.         DrawGrayLine (grayLineRect)
  1566.     END;
  1567.  
  1568.  
  1569. {$S ProcessGuts}
  1570. (*******************************************************************************
  1571. * Public: FixProcessInfoMenus
  1572. *
  1573. * If there’s enough memory to work with, the launch items in the File menu are
  1574. * enabled.
  1575. *******************************************************************************)
  1576.  
  1577.     PROCEDURE FixProcessInfoMenus (processInfoWindow: WindowPtr);
  1578.  
  1579.         VAR
  1580.             aMenu: MenuHandle; {Handle to any menu we’re checking on}
  1581.  
  1582.     BEGIN
  1583.         {$unused processInfoWindow}
  1584.         (* Undim the File menu items *)
  1585.         aMenu := GetMenuHandle (mFile);
  1586.         IF NOT FailLowMemory (0) THEN
  1587.             BEGIN
  1588.                 EnableItem (aMenu, iClose);
  1589.                 EnableItem (aMenu, iLaunchFore);
  1590.                 EnableItem (aMenu, iLaunchBack);
  1591.                 EnableItem (aMenu, iLaunchTo)
  1592.             END
  1593.     END;
  1594.  
  1595.  
  1596. {$S Main}
  1597. (*******************************************************************************
  1598. * Public: DoWindowClose
  1599. *
  1600. * As new kinds of windows are added to this application, this routine will have
  1601. * to be able to detect the new kind of window and dispatch to the routine that
  1602. * handles close requests for that kind of window.
  1603. *******************************************************************************)
  1604.  
  1605.     PROCEDURE DoWindowClose (eventWind: WindowPtr);
  1606.  
  1607.     BEGIN
  1608.         IF IsProcessInfoWindow (eventWind) THEN
  1609.             CloseProcessInfoWindow (eventWind);
  1610.     END;
  1611.  
  1612.  
  1613. {$S ProcessGuts}
  1614. (*******************************************************************************
  1615. * Public: IdleAllProcessWindows
  1616. *
  1617. * The process list window and process info windows each have their own idle
  1618. * routine defined in this source file, so the type of window is checked and the
  1619. * appropriate idle routine is called for that window.
  1620. *******************************************************************************)
  1621.  
  1622.     PROCEDURE IdleAllProcessWindows;
  1623.  
  1624.         VAR
  1625.             processWindow: WindowPtr; {Pointer to each process window being idled}
  1626.  
  1627.     BEGIN
  1628.         processWindow := FrontWindow;
  1629.  
  1630.         (* Loop through all windows in the window list *)
  1631.         WHILE processWindow <> NIL DO
  1632.             BEGIN
  1633.                 (* Call the appropriate idle routine if it’s a process window *)
  1634.                 IF IsProcessListWindow (processWindow) THEN
  1635.                     IdleProcessListWindow (processWindow)
  1636.                 ELSE IF IsProcessInfoWindow (processWindow) THEN
  1637.                     IdleProcessInfoWindow (processWindow);
  1638.  
  1639.                 (* Go to the next window in the window list *)
  1640.                 processWindow := WindowPtr(WindowPeek(processWindow)^.nextWindow)
  1641.             END
  1642.     END;
  1643.  
  1644.  
  1645. {$S ProcessGuts}
  1646. (*******************************************************************************
  1647. * Private: AppDAFilterProc - File filter procedure for apps and files with DAs
  1648. *
  1649. *     This is a Standard File file filter procedure that allows applications and
  1650. * any files with desk accessories in them to show up in the Standard File file
  1651. * list.
  1652. *
  1653. *     Checking to see whether a file is an application is easy enough.  Just
  1654. * check to see whether its type is APPL.  If it is, then it’s an application.
  1655. * Checking on desk accessories is trickier.  Desk accessories can be contained
  1656. * in any type of file.  So if a file isn’t doesn’t have the APPL type, I open
  1657. * the resource fork of the file using HOpenResFile and an access mode of
  1658. * fdRdPerm.  This allows me to open and close the resource file without worrying
  1659. * about that resource file being open by someone else because HOpenResFile with
  1660. * an access mode of fdRdPerm returns a unique access path to this routine.  When
  1661. * the file is open, I check for DRVR resources.  DRVR resources can be either
  1662. * desk accessories or device drivers.  I only want to show files containing desk
  1663. * accessories, so I check on the first character of the DRVR resource’s name.
  1664. * If it’s a null character, then the DRVR is a desk accessory.  If it’s any
  1665. * other character, then it’s a device driver and I ignore it.
  1666. *******************************************************************************)
  1667.  
  1668.     FUNCTION AppDAFilterProc (fileInfo: CInfoPBPtr): Boolean;
  1669.  
  1670.         CONST
  1671.             kShowIt = FALSE; {FALSE means I do not filter out...}
  1672.  
  1673.         VAR
  1674.             resRef:     Integer; {File ref num of file being tested}
  1675.             currResRef: Integer; {File ref number of current file}
  1676.             numDrvrs:   Integer; {Number of DRVR resources in file being tested}
  1677.             index:      Integer; {Index into resources of file being tested}
  1678.             drvrRsrc:   Handle;  {Handle to DRVR resource; always NIL master ptr}
  1679.             resID:      Integer; {Resource ID of DRVR resource; ignored}
  1680.             junkResType:ResType; {Resource type of DRVR resource; ignored}
  1681.             resName:    Str255;  {Resource name of DRVR resource}
  1682.  
  1683.     BEGIN
  1684.         IF fileInfo^.ioFlFndrInfo.fdType ='APPL' THEN
  1685.             AppDAFilterProc := kShowIt
  1686.         ELSE
  1687.             BEGIN
  1688.                 (* Assume we don’t show the file *)
  1689.                 AppDAFilterProc := NOT kShowIt;
  1690.  
  1691.                 (* Want to check rsrcs, not load ’em, including preload resources *)
  1692.                 SetResLoad (FALSE);
  1693.  
  1694.                 (* Save current res file refnum, open the specified rsrc file *)
  1695.                 currResRef := CurResFile;
  1696.                 resRef := HOpenResFile (fileInfo^.ioVRefNum,
  1697.                         LMGetCurDirStore, fileInfo^.ioNamePtr^, fsRdPerm);
  1698.  
  1699.                 (* If couldn’t open resource file, HOpenResFile returns -1 *)
  1700.                 IF (resRef <> -1) THEN
  1701.                     BEGIN
  1702.                         UseResFile (resRef);
  1703.  
  1704.                         (* Count number of DRVR resources in the file *)
  1705.                         numDrvrs := Count1Resources ('DRVR');
  1706.                         IF numDrvrs > 0 THEN
  1707.                             BEGIN
  1708.                                 (* For each DRVR, see if it’s a DA *)
  1709.                                 FOR index := 1 TO numDrvrs DO
  1710.                                     BEGIN
  1711.                                         drvrRsrc := Get1IndResource ('DRVR', index);
  1712.                                         GetResInfo (drvrRsrc, (*<*)resID, (*<*)junkResType,
  1713.                                                 (*<*)resName);
  1714.         
  1715.                                         (* If first char of name is null, it’s a DA *)
  1716.                                         IF resName [1] = CHR (0) THEN
  1717.                                             AppDAFilterProc := kShowIt
  1718.                                     END
  1719.                             END;
  1720.                         CloseResFile (resRef)
  1721.                     END;
  1722.         
  1723.                 (* Restore everything back to what it was *)
  1724.                 UseResFile (currResRef);
  1725.                 SetResLoad (TRUE)
  1726.             END
  1727.     END;
  1728.  
  1729.  
  1730. {$S ProcessGuts}
  1731. (*******************************************************************************
  1732. * Private: LaunchCycle - Attempt to launch a process
  1733. *
  1734. * This routine calls the LaunchProcess routine that’s in the UProcessUtils unit.
  1735. * The launchFile parameter specifies the file to launch.  The docList parameter
  1736. * specifies the list of documents to pass to the launched application for it to
  1737. * open or print.  The launchOptions parameter specifies the initial set of
  1738. * launch options to use when launching.  The the section titled “Specifying
  1739. * Launch Options” in the Process Manager chapter of Inside Macintosh VI for the
  1740. * a list and description of the launch options that you can pass in this
  1741. * parameter.
  1742. *
  1743. * If the Process Manager denies the launch, then LaunchProcess returns the
  1744. * resulting error code in the LaunchError flag.  If this happens and if the
  1745. * error happened to be that the machine is in 32-bit addressing mode and the
  1746. * application’s SIZE resource doesn’t have the 32-bit clean flag on, or if there
  1747. * isn’t enough memory to launch the application or desk accessory, then an alert
  1748. * is presented to the user asking if he or she wants to continue anyway.  If the
  1749. * user specifies that he or she does, then launch options are added to the ones
  1750. * passed in the launchOptions parameter which allow 32-bit unclean applications
  1751. * to launch or to allow the launch into available memory, and then LaunchProcess
  1752. * is called again.  This is repeated either until the application or desk
  1753. * accessory is successfully launched, the user chose not to launch it, or until
  1754. * an unrecoverable error occurs.
  1755. *******************************************************************************)
  1756.  
  1757.     PROCEDURE LaunchCycle (launchFile:    FSSpec;
  1758.                            docList:       DocListHnd;
  1759.                            launchOptions: Integer);
  1760.  
  1761.         VAR
  1762.             processNum:    ProcessSerialNumber; {Serial number of launched process}
  1763.             attemptLaunch: Boolean;             {TRUE if continuing launch attempt}
  1764.             result:        Integer;             {Result of caution alert}
  1765.             launchError:   OSErr;               {Launch error code}
  1766.             error:         OSErr;
  1767.             junkError:       OSErr;
  1768.  
  1769.     BEGIN
  1770.         (* Repeat until successful launch or cancelled launch *)
  1771.         REPEAT
  1772.             (* Attempt to launch the process *)
  1773.             error := LaunchProcess (launchFile, NIL, docList, launchOptions,
  1774.                     (*<*)processNum, (*<*)launchError);
  1775.  
  1776.             (* Check for launching errors *)
  1777.             IF launchError <> noErr THEN
  1778.                 BEGIN
  1779.                     (* There was a launching error, present to user *)
  1780.                     IF launchError = appModeErr THEN
  1781.                         BEGIN
  1782.                             (* Ask user if it’s OK to launch 32-bit unclean app *)
  1783.                             IF (ShowCautionOKCancelAlert (rMiscWrnMessages,
  1784.                                     kMiscWrnUncleanMsg, result) = noErr) & (result = ok) THEN
  1785.                                 BEGIN
  1786.                                     (* Try launch again, allowing 32-bit unclean app *)
  1787.                                     launchOptions := BOR (launchOptions,
  1788.                                             launchAllow24Bit);
  1789.                                     attemptLaunch := TRUE
  1790.                                 END
  1791.                             ELSE
  1792.                                 attemptLaunch := FALSE
  1793.                         END
  1794.                     ELSE IF launchError = memFullErr THEN
  1795.                         BEGIN
  1796.                             (* Ask user if it’s OK to launch w/ < requested memory *)
  1797.                             IF (ShowCautionOKCancelAlert (rMiscWrnMessages,
  1798.                                     kMiscWrnLaunchMemMsg, result) = noErr) & (result = ok) THEN
  1799.                                 BEGIN
  1800.                                     (* Try launch again, with less than requested mem *)
  1801.                                     launchOptions := BOR (launchOptions,
  1802.                                             launchUseMinimum);
  1803.                                     attemptLaunch := TRUE
  1804.                                 END
  1805.                             ELSE
  1806.                                 attemptLaunch := FALSE
  1807.                         END
  1808.                     ELSE
  1809.                         BEGIN
  1810.                             (* Some error we don’t handle happened *)
  1811.                             junkError := ShowStopAlert (rMiscErrMessages,
  1812.                                     kMiscErrUnknownMsg, result);
  1813.                             attemptLaunch := FALSE
  1814.                         END
  1815.                 END
  1816.             ELSE IF error <> noErr THEN
  1817.                 BEGIN
  1818.                     junkError := ShowStopAlert (rMiscErrMessages,
  1819.                             kMiscErrUnknownMsg, result);
  1820.                     attemptLaunch := FALSE
  1821.                 END
  1822.             ELSE
  1823.                 attemptLaunch := FALSE
  1824.         UNTIL NOT attemptLaunch;
  1825.     END;
  1826.  
  1827.  
  1828. {$S ProcessGuts}
  1829. (*******************************************************************************
  1830. * Public: DoLaunchInFront
  1831. *
  1832. * If the user is launching with documents, then only applications are presented
  1833. * to the user in the standard-file dialog.  If the user only wants to launch
  1834. * without any documents, then both applications and files containing desk
  1835. * accessories are presented to the user.
  1836. *******************************************************************************)
  1837.  
  1838.     PROCEDURE DoLaunchInFront;
  1839.  
  1840.         VAR
  1841.             reply:       StandardFileReply; {Reply from SFGetFile}
  1842.             typeList:    SFTypeList;        {List of file types for SF}
  1843.             launchSpec:  FSSpec;            {Location of selected app/DA}
  1844.             docList:     DocListHnd;        {Handle to the document list}
  1845.             gettingDocs: Boolean;           {True if user still getting docs}
  1846.             launchMode:  LaunchModeCode;    {Current launch mode}
  1847.             error:       OSErr;
  1848.  
  1849.     BEGIN
  1850.         (* Get the user’s choice for a file to launch *)
  1851.         launchMode := GetLaunchMode;
  1852.         IF launchMode = kJustLaunch THEN
  1853.             (* Just launching, so launch applications and DAs *)
  1854.             StandardGetFile (gAppDAFilterUPP, -1, @typeList, (*<*)reply)
  1855.         ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1856.             BEGIN
  1857.                 (* Launching with documents, so launch applications only *)
  1858.                 typeList [0] := 'APPL';
  1859.                 StandardGetFile (NIL, 1, @typeList, (*<*)reply)
  1860.             END;
  1861.  
  1862.         IF reply.sfGood THEN
  1863.             BEGIN
  1864.                 launchSpec := reply.sfFile;
  1865.  
  1866.                 (* Check to see if documents should be opened/printed as well *)
  1867.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1868.                     BEGIN
  1869.                         (* Create an empty list of documents *)
  1870.                         docList := CreateDocList (launchMode);
  1871.  
  1872.                         (* Keep getting documents until user chooses Cancel *)
  1873.                         gettingDocs := TRUE;
  1874.                         WHILE gettingDocs DO
  1875.                             BEGIN
  1876.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  1877.                                 IF reply.sfGood THEN
  1878.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  1879.                                 ELSE
  1880.                                     gettingDocs := FALSE
  1881.                             END
  1882.                     END
  1883.                 ELSE
  1884.                     docList := NIL;
  1885.  
  1886.                 (* Attempt to launch the application *)
  1887.                 LaunchCycle (launchSpec, docList, launchContinue);
  1888.  
  1889.                 (* Dispose of the document list, if there was one *)
  1890.                 IF docList <> NIL THEN
  1891.                     DisposeDocList (docList)
  1892.             END
  1893.     END;
  1894.  
  1895.  
  1896. {$S ProcessGuts}
  1897. (*******************************************************************************
  1898. * Public: DoLaunchInBack
  1899. *
  1900. *******************************************************************************)
  1901.  
  1902.     PROCEDURE DoLaunchInBack;
  1903.  
  1904.         VAR
  1905.             reply:       StandardFileReply; {Reply from SFGetFile}
  1906.             typeList:    SFTypeList;        {List of file types to diplay in SF}
  1907.             launchSpec:  FSSpec;            {Location of selected application}
  1908.             docList:     DocListHnd;        {Handle to the document list}
  1909.             gettingDocs: Boolean;           {True if user still getting docs}
  1910.             launchMode:  LaunchModeCode;    {Current launch mode}
  1911.             error:       OSErr;
  1912.  
  1913.     BEGIN
  1914.         (* Get the user’s choice for an application to launch *)
  1915.         typeList [0] := 'APPL';
  1916.         StandardGetFile (NIL, 1, @typeList, (*<*)reply);
  1917.  
  1918.         IF reply.sfGood THEN
  1919.             BEGIN
  1920.                 (* Convert working directory and file name to FSSpec *)
  1921.                 launchSpec := reply.sfFile;
  1922.  
  1923.                 launchMode := GetLaunchMode;
  1924.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1925.                     BEGIN
  1926.                         (* Create an empty list of documents *)
  1927.                         docList := CreateDocList (launchMode);
  1928.  
  1929.                         (* Keep getting documents until user chooses Cancel *)
  1930.                         gettingDocs := TRUE;
  1931.                         WHILE gettingDocs DO
  1932.                             BEGIN
  1933.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  1934.                                 IF reply.sfGood THEN
  1935.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  1936.                                 ELSE
  1937.                                     gettingDocs := FALSE
  1938.                             END
  1939.                     END
  1940.                 ELSE
  1941.                     docList := NIL;
  1942.  
  1943.                 (* Attempt to launch the application *)
  1944.                 LaunchCycle (launchSpec, docList, launchContinue +
  1945.                         launchDontSwitch);
  1946.  
  1947.                 (* Dispose of the document list, if there was one *)
  1948.                 IF docList <> NIL THEN
  1949.                     DisposeDocList (docList)
  1950.             END
  1951.     END;
  1952.  
  1953.  
  1954. {$S ProcessGuts}
  1955. (*******************************************************************************
  1956. * Public: DoLaunchTo
  1957. *
  1958. *******************************************************************************)
  1959.  
  1960.     PROCEDURE DoLaunchTo;
  1961.  
  1962.         VAR
  1963.             reply:       StandardFileReply; {Reply from SFGetFile}
  1964.             typeList:    SFTypeList;        {List of file types to diplay in SF}
  1965.             launchSpec:  FSSpec;            {Location of selected file}
  1966.             docList:     DocListHnd;        {Handle to the document list}
  1967.             gettingDocs: Boolean;           {True if user still getting docs}
  1968.             launchMode:  LaunchModeCode;    {Current launch mode}
  1969.             error:       OSErr;
  1970.  
  1971.     BEGIN
  1972.         (* Get the user’s choice for a file to launch *)
  1973.         launchMode := GetLaunchMode;
  1974.         IF launchMode = kJustLaunch THEN
  1975.             (* Just launching, so launch applications and DAs *)
  1976.             StandardGetFile (gAppDAFilterUPP, -1, @typeList, (*<*)reply)
  1977.         ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1978.             BEGIN
  1979.                 (* Launching with documents, so launch applications only *)
  1980.                 typeList [0] := 'APPL';
  1981.                 StandardGetFile (NIL, 1, @typeList, (*<*)reply)
  1982.             END;
  1983.  
  1984.         IF reply.sfGood THEN
  1985.             BEGIN
  1986.                 (* Convert working directory and file name to FSSpec *)
  1987.                 launchSpec := reply.sfFile;
  1988.  
  1989.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1990.                     BEGIN
  1991.                         (* Create an empty list of documents *)
  1992.                         docList := CreateDocList (launchMode);
  1993.  
  1994.                         (* Keep getting documents until user chooses Cancel *)
  1995.                         gettingDocs := TRUE;
  1996.                         WHILE gettingDocs DO
  1997.                             BEGIN
  1998.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  1999.                                 IF reply.sfGood THEN
  2000.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  2001.                                 ELSE
  2002.                                     gettingDocs := FALSE
  2003.                             END
  2004.                     END
  2005.                 ELSE
  2006.                     docList := NIL;
  2007.  
  2008.                 (* Attempt to launch the application or DA *)
  2009.                 LaunchCycle (launchSpec, docList, launchAllow24Bit);
  2010.  
  2011.                 (* Dispose of the document list, if there was one *)
  2012.                 IF docList <> NIL THEN
  2013.                     DisposeDocList (docList)
  2014.             END
  2015.     END;
  2016.  
  2017.  
  2018. {$S ProcessGuts}
  2019. (*******************************************************************************
  2020. * Public: DoLaunchMode
  2021. *
  2022. * SetLaunchMode does most of the work, and there isn’t much to do.
  2023. *******************************************************************************)
  2024.  
  2025.     PROCEDURE DoLaunchMode (modeItem: Integer);
  2026.  
  2027.     BEGIN
  2028.         CASE modeItem OF
  2029.             iJustLaunch:
  2030.                 SetLaunchMode (kJustLaunch);
  2031.             iOpenLaunch:
  2032.                 SetLaunchMode (kOpenLaunch);
  2033.             iPrintLaunch:
  2034.                 SetLaunchMode (kPrintLaunch)
  2035.         END
  2036.     END;
  2037.  
  2038.  
  2039. {$S ProcessGuts}
  2040. (*******************************************************************************
  2041. * Public: DoBringProcessToFront
  2042. *
  2043. * The List Manager is called to get each selection in the process list window.
  2044. * SetFrontProcess is called with the process serial number of each selected
  2045. * process.  They aren’t immediately brought to the front when SetFrontProcess is
  2046. * called.  Instead, they are scheduled to come to the front in the same order as
  2047. * they were presented to SetFrontProcess.  Once ProcDoggie reenters the main
  2048. * event loop, the Process Manager brings each scheduled process to the front in
  2049. * turn.
  2050. *
  2051. * At the moment, I can’t get ProcDoggie itself to be scheduled.  I assume it’s
  2052. * because SetFrontProcess checks to see if process serial number you passed it
  2053. * is the same as the process serial number of the current process.  If it is, it
  2054. * doesn’t bother to schedule the process.  I’m not quite sure how to work around
  2055. * that.
  2056. *
  2057. * I checked with the Process Manager source and the above explanation is correct.
  2058. * -- Quinn 10 Mar 1997
  2059. *******************************************************************************)
  2060.  
  2061.     PROCEDURE DoBringProcessToFront (processListWindow: WindowPtr);
  2062.  
  2063.         CONST
  2064.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2065.  
  2066.         VAR
  2067.             procList:     ListHandle;         {Handle to List Mgr process list}
  2068.             currCell:     Point;              {Cell that has selection}
  2069.             listInfo:     ProcessListInfoRec; {Process info from List Mgr list}
  2070.             gotSelection: Boolean;            {T if got sel’d cell, F if no more}
  2071.             listInfoLen:  Integer;            {Length of list info in bytes}
  2072.             error:        OSErr;
  2073.  
  2074.     BEGIN
  2075.         (* Get the List Manager’s copy of the process list *)
  2076.         procList := ListHandle(GetWRefCon (processListWindow));
  2077.  
  2078.         (* Keep looping until all selected processes have been brought to front *)
  2079.         currCell.v := 0;
  2080.         currCell.h := 0;
  2081.         gotSelection := TRUE;
  2082.         WHILE gotSelection DO
  2083.             BEGIN
  2084.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2085.                 IF gotSelection THEN
  2086.                     BEGIN
  2087.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2088.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2089.                                 procList);
  2090.                         error := SetFrontProcess (listInfo.serialNumber);
  2091.                         currCell.v := currCell.v + 1
  2092.                     END
  2093.             END
  2094.     END;
  2095.  
  2096.  
  2097. {$S ProcessGuts}
  2098. (*******************************************************************************
  2099. * Public: DoGetProcessInfo
  2100. *
  2101. * This routine loops until Process Information windows for all selected
  2102. * processes in the Process List window are displayed.  Information for each
  2103. * process in the process list is retrieved from the list itself.  Then, that
  2104. * process is compared against all existing Process Information windows.  If a
  2105. * Process Information window already exists for that process, then that window
  2106. * is simply activated and DoGetProcessInfo exits.  Otherwise, the Process
  2107. * Manager is called to retrieve information for that process.  A new Process
  2108. * Information window is created, and its contents are set to the information
  2109. * retrieved for the process.
  2110. *******************************************************************************)
  2111.  
  2112.     PROCEDURE DoGetProcessInfo (processListWindow: WindowPtr);
  2113.  
  2114.         CONST
  2115.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2116.  
  2117.         VAR
  2118.             procList:          ListHandle;         {Handle to List Mgr proc list}
  2119.             currCell:          Point;              {Cell that has selection}
  2120.             listInfo:          ProcessListInfoRec; {Proc info from List Mgr list}
  2121.             gotSelection:      Boolean;            {T if got sel’d cell, F if none}
  2122.             listInfoLen:       Integer;            {Length of list info in bytes}
  2123.             processInfo:       ProcessInfoRec;     {Info about selected processes}
  2124.             procName:          Str255;             {Name of selected processes}
  2125.             procSpec:          FSSpec;             {File spec of sel’d processes}
  2126.             processInfoWindow: WindowPtr;          {Ptr to new process info window}
  2127.             psnHandle:         Handle;             {Handle to PSN of chosen proc}
  2128.             existingWindow:    WindowPtr;          {Proc info wind if already open}
  2129.             error:             OSErr;
  2130.  
  2131.         PROCEDURE HandleError (messageClass: Integer;
  2132.                                messageIndex: Integer);
  2133.  
  2134.             VAR
  2135.                 junkError: OSErr;
  2136.                 result: Integer; {Result of alert; ignored}
  2137.  
  2138.         BEGIN
  2139.             IF processInfoWindow <> NIL THEN
  2140.                 CloseProcessInfoWindow (processInfoWindow);
  2141.             junkError := ShowStopAlert (messageClass, messageIndex, result);
  2142.             gError := noErr;
  2143.             EXIT (DoGetProcessInfo)
  2144.         END;
  2145.  
  2146.     BEGIN
  2147.         (* Get the List Manager’s copy of the process list *)
  2148.         procList := ListHandle(GetWRefCon (processListWindow));
  2149.  
  2150.         (* Keep looping until all selected processes have been brought to front *)
  2151.         currCell.v := 0;
  2152.         currCell.h := 0;
  2153.         gotSelection := TRUE;
  2154.         WHILE gotSelection DO
  2155.             BEGIN
  2156.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2157.                 IF gotSelection THEN
  2158.                     BEGIN
  2159.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2160.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2161.                                 procList);
  2162.  
  2163.                         (* See if proc info wind already exists for selected proc *)
  2164.                         existingWindow := FindProcessInfoWindow (listInfo.
  2165.                                 serialNumber);
  2166.                         IF existingWindow <> NIL THEN
  2167.                             SelectWindow (existingWindow)
  2168.                         ELSE
  2169.                             BEGIN
  2170.                                 (* Get information about an open process *)
  2171.                                 processInfo.processInfoLength :=
  2172.                                         SIZEOF (ProcessInfoRec);
  2173.                                 processInfo.processName := @procName;
  2174.                                 processInfo.processAppSpec := @procSpec;
  2175.                                 error := GetProcessInformation (listInfo.serialNumber,
  2176.                                         (*◊*)processInfo);
  2177.                                 IF error <> noErr THEN
  2178.                                     HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  2179.  
  2180.                                 (* Create the process information window *)
  2181.                                 processInfoWindow := CreateProcessInfoWindow;
  2182.                                 IF processInfoWindow <> NIL THEN
  2183.                                     BEGIN
  2184.                                         (* Put handle to PSN into refCon *)
  2185.                                         psnHandle := NewHandleMargin (SIZEOF
  2186.                                                 (ProcessSerialNumber), kAllocApp,
  2187.                                                 NOT kAllocClr);
  2188.                                         IF psnHandle = NIL THEN
  2189.                                             HandleError (rMemErrMessages,
  2190.                                                     kMemErrProcInfoOpenMsg);
  2191.                                         BlockMoveData (Ptr(@processInfo.processNumber),
  2192.                                                 psnHandle^, SIZEOF (ProcessSerialNumber));
  2193.                                         SetWRefCon (processInfoWindow,
  2194.                                                 LongInt(psnHandle));
  2195.  
  2196.                                         (* Update dlog items to reflect proc info *)
  2197.                                         SetUpProcessInfoItems (processInfoWindow,
  2198.                                                 processInfo);
  2199.                                     END
  2200.                                 ELSE
  2201.                                     gotSelection := FALSE
  2202.                             END;
  2203.  
  2204.                         (* Go to the next cell *)
  2205.                         currCell.v := currCell.v + 1
  2206.                     END
  2207.             END
  2208.     END;
  2209.  
  2210.  
  2211. {$S ProcessGuts}
  2212. (*******************************************************************************
  2213. * Public: DoTerminateProcess
  2214. *
  2215. * The List Manager is used to get all of the selected processes in
  2216. * processListWindow.  The process serial number of each of these processes is
  2217. * extracted and is then used when calling TerminateProcess.
  2218. *******************************************************************************)
  2219.  
  2220.     PROCEDURE DoTerminateProcess (processListWindow: WindowPtr);
  2221.  
  2222.         CONST
  2223.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2224.  
  2225.         VAR
  2226.             procList:     ListHandle;         {Handle to List Mgr process list}
  2227.             currCell:     Point;              {Cell that has selection}
  2228.             listInfo:     ProcessListInfoRec; {Process info from List Mgr list}
  2229.             listInfoLen:  Integer;            {Length of list info in bytes}
  2230.             gotSelection: Boolean;            {T if got sel’d cell, F if none}
  2231.             error:        OSErr;
  2232.  
  2233.         PROCEDURE HandleError (messageClass: Integer;
  2234.                                messageIndex: Integer);
  2235.  
  2236.             VAR
  2237.                 junkError: OSErr;
  2238.                 result: Integer; {Result of alert; ignored}
  2239.  
  2240.         BEGIN
  2241.             junkError := ShowStopAlert (messageClass, messageIndex, result);
  2242.             gError := noErr;
  2243.             EXIT (DoTerminateProcess)
  2244.         END;
  2245.  
  2246.     BEGIN
  2247.         (* Get the List Manager’s copy of the process list *)
  2248.         procList := ListHandle(GetWRefCon (processListWindow));
  2249.  
  2250.         (* Keep looping until all selected processes have been terminated *)
  2251.         currCell.v := 0;
  2252.         currCell.h := 0;
  2253.         gotSelection := TRUE;
  2254.         WHILE gotSelection DO
  2255.             BEGIN
  2256.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2257.                 IF gotSelection THEN
  2258.                     BEGIN
  2259.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2260.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2261.                                 procList);
  2262.  
  2263.                         (* Kill the specified process *)
  2264.                         error := TerminateProcess (listInfo.serialNumber);
  2265.                         IF error <> noErr THEN
  2266.                             HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  2267.  
  2268.                         (* Go to the next cell *)
  2269.                         currCell.v := currCell.v + 1
  2270.                     END
  2271.             END
  2272.     END;
  2273.  
  2274. {$S Startup}
  2275. (*******************************************************************************
  2276. * Public: InitProcessGuts
  2277. *******************************************************************************)
  2278.  
  2279.     PROCEDURE InitProcessGuts;
  2280.     BEGIN
  2281.         gAppDAFilterUPP := NewFileFilterProc(@AppDAFilterProc);
  2282.         gProcessListLDEF := NewListDefProc(@ProcessListLDEF);
  2283.         gEqualPSNUPP := NewListSearchProc(ListSearchProcPtr(@EqualPSN));
  2284.     END;
  2285.     
  2286. END.
  2287.